/*
 * Copyright (c) 2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_pwm.h"
#include "iot_i2c.h"
#include "iot_gpio.h"
#include "hi_timer.h"
#include "hi_gpio.h"
#include "app_demo_multi_sample.h"
#include "ssd1306_oled.h"
#include "app_demo_i2c_oled.h"
#include "app_demo_config.h"

#define IOT_GPIO_INDEX_10 10
#define IOT_GPIO_INDEX_11 11
#define IOT_GPIO_INDEX_12 12

#define IOT_GPIO_INDEX_2 2                //普通输出口，控制数码管，南北向，SDI
#define IOT_GPIO_INDEX_5 5                //普通输出口，控制数码管，东西向，SDI
#define IOT_GPIO_INDEX_6 6                //普通输出口，控制数码管，双向共用，SCLK
#define IOT_GPIO_INDEX_7 7                //普通输出口，控制数码管，双向共用，LOAD

#define IO_FUNC_GPIO_9_PWM0_OUT 5
#define IO_FUNC_GPIO_OUT 0

#define COUNT_MAX_SECOND        (4294967296)
#define DELAY_CYCLE_COUNT   (20000)
#define CN_QUEUE_WAITTIMEOUT   1000
#define DATA_OUT_OF_BOUND (-1)
#define DATA_OUT_OF_BOUND (-1)
#define CN_QUEUE_MSGNUM 16
#define CN_QUEUE_MSGSIZE (sizeof(hi_pvoid))
#define MODULUS_OR_REMAINDER (10)
#define COUNT_RESET ((hi_u8)0x0)
#define CN_QUEUE_WAITTIMEOUT   1000

unsigned char g_trafficAutoModeCurrent = TRAFFIC_AUTO_MODE;

int Timer_Stra_NS_G = 10;
int Timer_Stra_NS_Y = 3;
int Timer_Stra_EW_G = 10;
int Timer_Stra_EW_Y = 3;

int Timer_Stra_NS_G_Auto = 10;
int Timer_Stra_EW_G_Auto = 10;

extern int Timer_Stra_NS_G_remote;
extern int Timer_Stra_NS_Y_remote;
extern int Timer_Stra_EW_G_remote;
extern int Timer_Stra_EW_Y_remote;

extern unsigned char auto_count_flag;
extern unsigned char Msg_Cmd_change;

extern unsigned char Conges_Buf[8];
unsigned char Conges_Region_1 = 0;
unsigned char Conges_Region_2 = 0;
unsigned char Conges_Region_3 = 0;
unsigned char Conges_Region_4 = 0;
unsigned char Time_Add_Flag = 0;
unsigned char Time_Sub_Flag = 0;

const unsigned char table[] = 
{0xc0,0xf9,0xa4,0xb0,0x99,
0x92,0x82,0xf8,0x80,0x90,
0xff,0x00,0x90,0x96,0xaf,
0xc0,0x89,0xc7,0x8e,0xc1,0x7f}; //共阳极数码管码表
                                //0-9，全灭，全亮...

/*数码管显示函数*/
void Display_DigitalTube(unsigned char Shi_Wei_NS, unsigned char Ge_Wei_NS, unsigned char Shi_Wei_EW, unsigned char Ge_Wei_EW)
{
    unsigned char k;
	unsigned char n = Ge_Wei_NS;
	unsigned char m = Shi_Wei_NS;
    unsigned char x = Ge_Wei_EW;
	unsigned char y = Shi_Wei_EW;
        
    for(k=0; k<8; k++)  //74hc595两位共阳数码管，左移入数据
    {                   //先压入个位
        if(n & 0x80)    //取出最高位（74hc595先入高位）
        {
            GpioControl(IOT_GPIO_INDEX_2, IOT_GPIO_INDEX_2,                   
                    IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE1, IO_FUNC_GPIO_OUT);
        }           
        else 
        {
            GpioControl(IOT_GPIO_INDEX_2, IOT_GPIO_INDEX_2,                   
                    IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0, IO_FUNC_GPIO_OUT);
        }               
        n <<= 1;        //数据左移一位
        if(x & 0x80)    //再压入十位
        {
            GpioControl(IOT_GPIO_INDEX_5, IOT_GPIO_INDEX_5,                   
                    IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE1, IO_FUNC_GPIO_OUT);
        }           
        else 
        {
            GpioControl(IOT_GPIO_INDEX_5, IOT_GPIO_INDEX_5,                   
                    IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0, IO_FUNC_GPIO_OUT); 
        }               
        x <<= 1;        	
        GpioControl(IOT_GPIO_INDEX_6, IOT_GPIO_INDEX_6,        //锁存信号
                    IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0, IO_FUNC_GPIO_OUT);
        usleep(1);
        GpioControl(IOT_GPIO_INDEX_6, IOT_GPIO_INDEX_6,                   
                    IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE1, IO_FUNC_GPIO_OUT);       		
    }		
    for(k=0; k<8; k++)  
    {
        if(m & 0x80)
        {
            GpioControl(IOT_GPIO_INDEX_2, IOT_GPIO_INDEX_2,                   
                    IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE1, IO_FUNC_GPIO_OUT);
        }           
        else 
        {
            GpioControl(IOT_GPIO_INDEX_2, IOT_GPIO_INDEX_2,                   
                    IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0, IO_FUNC_GPIO_OUT);
        }               
        m <<= 1;  
        if(y & 0x80)
        {
            GpioControl(IOT_GPIO_INDEX_5, IOT_GPIO_INDEX_5,                   
                     IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE1, IO_FUNC_GPIO_OUT);
        }           
        else 
        {
            GpioControl(IOT_GPIO_INDEX_5, IOT_GPIO_INDEX_5,                   
                    IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0, IO_FUNC_GPIO_OUT);
        }               
        y <<= 1;    	
        GpioControl(IOT_GPIO_INDEX_6, IOT_GPIO_INDEX_6,                   
                        IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0, IO_FUNC_GPIO_OUT);
        usleep(1);
        GpioControl(IOT_GPIO_INDEX_6, IOT_GPIO_INDEX_6,                   
                    IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE1, IO_FUNC_GPIO_OUT);       		
    }
        
    GpioControl(IOT_GPIO_INDEX_7, IOT_GPIO_INDEX_7,                   
                    IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE1, IO_FUNC_GPIO_OUT);
    usleep(1);    
    GpioControl(IOT_GPIO_INDEX_7, IOT_GPIO_INDEX_7,                   
                    IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0, IO_FUNC_GPIO_OUT);		     			
}

/*交通灯时间显示函数*/
void Display_LightTime()
{
    unsigned char num_Ge = 0;
    unsigned char num_Shi = 0;
    unsigned char Shi_Wei_NS, Ge_Wei_NS, Shi_Wei_EW, Ge_Wei_EW;
    unsigned char Direc_NSEW = 0;
    unsigned char count_G = 0;
    unsigned char count_Y = 0;
    unsigned char count_R = 0;

    switch (GetKeyStatus(CURRENT_TYPE)) 
    {
        case STRA_NS_GREEN:
            count_G = Timer_Stra_NS_G;          //红灯时长比绿灯多3秒
            count_R = (Timer_Stra_NS_G + 3);    //“count_G”代表南北方向绿灯时长
            Direc_NSEW = 0;
            break;
        case STRA_NS_YELLOW:
            count_Y = Timer_Stra_NS_Y;
            Direc_NSEW = 1;
            break;
        case STRA_EW_GREEN:
            count_R = Timer_Stra_EW_G;          //这里是当行车方向切换后，变量也应该调换
            count_G = (Timer_Stra_EW_G + 3);    //“count_R”代表东西方向绿灯时长
            Direc_NSEW = 2;
            break;
        case STRA_EW_YELLOW:
            count_Y = Timer_Stra_EW_Y;
            Direc_NSEW = 3;
            break;

        default:
            break;
    }
    
    if (Direc_NSEW == 0 || Direc_NSEW == 2)
    {
        if(count_R == 99)
        {
            Ge_Wei_EW = table[9];
            Shi_Wei_EW = table[9];
        }       
        else 
        {
            if(count_R < 10)
            {
                Ge_Wei_EW = table[count_R];
                Shi_Wei_EW = table[10];
            }
            else
            {
                num_Ge = count_R % 10;
                num_Shi = count_R / 10;
                Ge_Wei_EW = table[num_Ge];
                Shi_Wei_EW = table[num_Shi];
            }
        }

        if(count_G == 99)
        {
            Ge_Wei_NS = table[9];
            Shi_Wei_NS = table[9];
        }       
        else 
        {
            if(count_G < 10)
            {
                Ge_Wei_NS = table[count_G];
                Shi_Wei_NS = table[10];
            }
            else
            {
                num_Ge = count_G % 10;
                num_Shi = count_G / 10;
                Ge_Wei_NS = table[num_Ge];
                Shi_Wei_NS = table[num_Shi];
            }
        }
        Display_DigitalTube(Shi_Wei_NS,Ge_Wei_NS,Shi_Wei_EW,Ge_Wei_EW);
    }
    
    if (Direc_NSEW == 1 || Direc_NSEW == 3)
    { 
        Ge_Wei_NS = table[count_Y];
        Shi_Wei_NS = table[10];
        Ge_Wei_EW = table[count_Y];
        Shi_Wei_EW = table[10];
        Display_DigitalTube(Shi_Wei_NS,Ge_Wei_NS,Shi_Wei_EW,Ge_Wei_EW);
    }
  
}

/* traffic auto mode */
void TrafficAutoModeSample(void)
{
    switch (GetKeyStatus(CURRENT_TYPE)) 
    {
        case STRA_NS_GREEN:
            SetKeyType(STRA_NS_GREEN);
            GpioControl(IOT_GPIO_INDEX_10, IOT_GPIO_INDEX_10,                   
                        IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0, IO_FUNC_GPIO_OUT);   
            GpioControl(IOT_GPIO_INDEX_11, IOT_GPIO_INDEX_11,                   
                        IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0, IO_FUNC_GPIO_OUT);   
            break;
        case STRA_NS_YELLOW:
            SetKeyType(STRA_NS_YELLOW);
            GpioControl(IOT_GPIO_INDEX_10, IOT_GPIO_INDEX_10,                   
                        IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0, IO_FUNC_GPIO_OUT);   
            GpioControl(IOT_GPIO_INDEX_11, IOT_GPIO_INDEX_11,                   
                        IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE1, IO_FUNC_GPIO_OUT);
            break;
        case STRA_EW_GREEN:
            SetKeyType(STRA_EW_GREEN);
            GpioControl(IOT_GPIO_INDEX_10, IOT_GPIO_INDEX_10,                   
                        IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE1, IO_FUNC_GPIO_OUT);   
            GpioControl(IOT_GPIO_INDEX_11, IOT_GPIO_INDEX_11,                   
                        IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0, IO_FUNC_GPIO_OUT); 
            break;
        case STRA_EW_YELLOW:
            SetKeyType(STRA_EW_YELLOW);
            GpioControl(IOT_GPIO_INDEX_10, IOT_GPIO_INDEX_10,                   
                        IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE1, IO_FUNC_GPIO_OUT);   
            GpioControl(IOT_GPIO_INDEX_11, IOT_GPIO_INDEX_11,                   
                        IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE1, IO_FUNC_GPIO_OUT);
            break;

        default:
            break;
    }
}

/*智能控制交通灯时间*/
void Intelligent_Time_Func()
{
    unsigned char Half_Time_G = 0;
    unsigned char Half_Time_Temp = 0;
      
    if (GetKeyStatus(CURRENT_TYPE) == STRA_NS_GREEN)
    {
        Half_Time_Temp = Timer_Stra_NS_G_Auto;
        Half_Time_G = (Half_Time_Temp/2);       
    }
    else if(GetKeyStatus(CURRENT_TYPE) == STRA_EW_GREEN)
    {
        Half_Time_Temp = Timer_Stra_EW_G_Auto;
        Half_Time_G = (Half_Time_Temp/2);
    }
    //某行车方向上的四个检测区域内，有一个区域不通畅的时间超过绿灯时间的一半，就需要增加绿灯时长
    if (Conges_Region_1 >= Half_Time_G || Conges_Region_2 >= Half_Time_G || Conges_Region_3 >= Half_Time_G || Conges_Region_4 >= Half_Time_G)
    {
        Time_Add_Flag = 1;
    }
    //某行车方向上的四个检测区域通畅时间都大于绿灯时间的一半，则需要减少绿灯时长
    if (Conges_Region_1 < Half_Time_G && Conges_Region_2 < Half_Time_G && Conges_Region_3 < Half_Time_G && Conges_Region_4 < Half_Time_G)
    {
        Time_Sub_Flag = 1;
    }  
}

/* 定时器回调函数 */
void Timer1Callback(unsigned int arg)
{
        if (GetKeyStatus(CURRENT_MODE) == TRAFFIC_AUTO_MODE)
        {
            if (GetKeyStatus(CURRENT_TYPE) == STRA_NS_GREEN)
            {
                if(Conges_Buf[0] != 0)      //每秒钟检测一次
                {
                    Conges_Region_1++;      //当有区域不通畅时就加一
                }
                if(Conges_Buf[1] != 0)
                {
                    Conges_Region_2++;
                }
                if(Conges_Buf[2] != 0)
                {
                    Conges_Region_3++;
                }
                if(Conges_Buf[3] != 0)
                {
                    Conges_Region_4++;
                }     
            }

            if(GetKeyStatus(CURRENT_TYPE) == STRA_EW_GREEN)
            {
                if(Conges_Buf[4] != 0)
                {
                    Conges_Region_1++;
                }
                if(Conges_Buf[5] != 0)
                {
                    Conges_Region_2++;
                }
                if(Conges_Buf[6] != 0)
                {
                    Conges_Region_3++;
                }
                if(Conges_Buf[7] != 0)
                {
                    Conges_Region_4++;
                }
            }
        }

        switch (GetKeyStatus(CURRENT_TYPE))                 //这里GetKeyStatus(CURRENT_TYPE)可以承接
        {                                                   //之前模式的type
            case STRA_NS_GREEN:
                if(Msg_Cmd_change == 1)                     //检查是否为远程指令
                {
                    Timer_Stra_NS_G = Timer_Stra_NS_G_remote;
                    Msg_Cmd_change = 0;                     //标志复位
                }
                // printf("STRA_NS_GREEN\r\n");
                // printf("TimeCount: %d s\r\n",Timer_Stra_NS_G);
                Timer_Stra_NS_G--;                          //计数值递减
                if(Timer_Stra_NS_G <= 0)                    //倒计时结束
                {
                    if (auto_count_flag == 0)               //如果是自动控制模式
                    {
                        
                        Intelligent_Time_Func();
                        if (Time_Add_Flag == 1)
                        {
                            Time_Add_Flag = 0;
                            if (Timer_Stra_NS_G_Auto < 16)
                            {
                                Timer_Stra_NS_G_Auto += 2;
                            }                           
                        }
                        if (Time_Sub_Flag == 1)
                        {
                            Time_Sub_Flag = 0;
                            if (Timer_Stra_NS_G_Auto > 6)
                            {
                                Timer_Stra_NS_G_Auto -= 2;
                            }                           
                        }                        
                        Timer_Stra_NS_G = Timer_Stra_NS_G_Auto;     //计数值复位
                    }
                    else                                            //如果是远程控制模式
                    {
                        Timer_Stra_NS_G = Timer_Stra_NS_G_remote;   //计数值复位
                    } 
                    SetKeyType(STRA_NS_YELLOW);                     //切换交通灯状态
                }
                break;
            case STRA_NS_YELLOW:
                if(Msg_Cmd_change == 1)
                {
                    Timer_Stra_NS_Y = Timer_Stra_NS_Y_remote;
                    Msg_Cmd_change = 0;
                }
                // printf("STRA_NS_YELLOW\r\n");
                Timer_Stra_NS_Y--;
                if(Timer_Stra_NS_Y <= 0)
                {
                    SetKeyType(STRA_EW_GREEN);         //切换交通灯状态
                    Timer_Stra_NS_Y = 3;               //计数值复位
                    Conges_Region_1 = 0;               //复位各区域拥堵时间计数
                    Conges_Region_2 = 0;               
                    Conges_Region_3 = 0;
                    Conges_Region_4 = 0;
                }               
                break;
            case STRA_EW_GREEN:
                if(Msg_Cmd_change == 1)
                {
                    Timer_Stra_EW_G = Timer_Stra_EW_G_remote;
                    Msg_Cmd_change = 0;
                }
                // printf("STRA_EW_GREEN\r\n");
                // printf("TimeCount: %d s\r\n",Timer_Stra_EW_G);              
                Timer_Stra_EW_G--;
                if(Timer_Stra_EW_G <= 0)
                {
                    if (auto_count_flag == 0)
                    {
                        Intelligent_Time_Func();
                        if (Time_Add_Flag == 1)
                        {
                            Time_Add_Flag = 0;
                            if (Timer_Stra_EW_G_Auto < 16)
                            {
                                Timer_Stra_EW_G_Auto += 2;
                            }                           
                        }
                        if (Time_Sub_Flag == 1)
                        {
                            Time_Sub_Flag = 0;
                            if (Timer_Stra_EW_G_Auto > 6)
                            {
                                Timer_Stra_EW_G_Auto -= 2;
                            }                           
                        }
                        Timer_Stra_EW_G = Timer_Stra_EW_G_Auto;     //计数值复位
                    }
                    else
                    {
                        Timer_Stra_EW_G = Timer_Stra_EW_G_remote;
                    }  
                    SetKeyType(STRA_EW_YELLOW);                 
                }
                break;
            case STRA_EW_YELLOW:
                if(Msg_Cmd_change == 1)
                {
                    Timer_Stra_EW_Y = Timer_Stra_EW_Y_remote;
                    Msg_Cmd_change = 0;
                }
                // printf("STRA_EW_YELLOW\r\n");
                Timer_Stra_EW_Y--;
                if(Timer_Stra_EW_Y <= 0)
                {
                    SetKeyType(STRA_NS_GREEN);
                    Timer_Stra_EW_Y = 3;               //计数值复位
                    Conges_Region_1 = 0;               //复位各区域拥堵时间计数
                    Conges_Region_2 = 0;               
                    Conges_Region_3 = 0;
                    Conges_Region_4 = 0;
                }
                break;

            default:
                break;
        }
}

void SoftwareTimersTaskEntry(void)
{
    unsigned int timerId1;
    unsigned int ret;

    /* 创建周期性软件定时器，时间为1000ms,启动到1000ms数时执行回调函数1 */
    ret = hi_timer_create(&timerId1);
    if (ret != HI_ERR_SUCCESS) 
    {
        printf("Failed to create timer 1\r\n");
    }

    ret = hi_timer_start(timerId1, HI_TIMER_TYPE_PERIOD, 1000, Timer1Callback, 0); /* 1000: timer 1000ms */
    if (ret != HI_ERR_SUCCESS) 
    {
        printf("Failed to start timer 1\r\n");
    }
}

#define TIMER_TASK_STACK  (1024 * 4)

static void TimerTask(void)
{
    osThreadAttr_t attr;
    IoTWatchDogDisable();

    attr.name = "TrafficLightDemo";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = TIMER_TASK_STACK;
    attr.priority = osPriorityNormal;   //优先级24

    if (osThreadNew((osThreadFunc_t)SoftwareTimersTaskEntry, NULL, &attr) == NULL) 
    {
        printf("[TrafficLight] Falied to create SoftwareTimersTaskEntry!\n");
    }
}

SYS_RUN(TimerTask);
